<template>
  <div class="dynamic-tabs">
    <TransitionGroup
      enter-active-class="tab-item-in"
      leave-active-class="tab-item-out"
    >
      <div
        v-for="tab in tabs"
        :key="tab.id"
        class="tab-item"
        :class="{ active: tab.id === currentTabID }"
        @click="activateTab(tab.id)"
      >
        <span>{{ tab.title }}</span>
        <el-button
          text
          circle
          :icon="CloseBold"
          class="close-btn"
          @click="closeTab(tab.id)"
        />
      </div>
    </TransitionGroup>
    <el-button text :icon="Plus" class="add-tab-btn" @click="createTab()" />
  </div>
</template>

<script setup lang="ts">
import { onMounted, ref } from "vue";
import { Plus, CloseBold } from "@element-plus/icons-vue";

onMounted(() => {
  // 检查是否存在标签
  tabs.value = JSON.parse(sessionStorage.getItem("tabs") || "{}");
  // 获取当前标签
  currentTabID.value = sessionStorage.getItem("activeTab") || "";
  //判断是否有存在标签
  const keys = Object.keys(tabs.value);
  // 如果没有标签则返回
  if (keys.length === 0) return;
  // 判断ID是否存在
  if (!keys.includes(currentTabID.value)) return;
  // 激活标签
  emit("changeTab", currentTabID.value);
});

// 定义标签页接口
interface Tab {
  id: string;
  title: string;
}
// 标签页对象
const tabs = ref<{ [key: string]: Tab }>({});
// 当前激活标签页 ID
const currentTabID = ref<string | null>(null);

// 定义事件
const emit = defineEmits<{
  (event: "addTab"): void;
  (event: "changeTab", tabID: string): void;
  (event: "closeTab", tabID: string, tabCount: number): void;
}>();

/** 添加标签页 */
const addPage = (tabID: string, title: string): number => {
  // 创建新标签页对象
  const newTab: Tab = {
    id: tabID,
    title,
  };
  // 添加到标签页对象
  tabs.value[tabID] = newTab;
  // 激活新标签页
  activateTab(tabID);
  // 返回标签页数量
  return Object.keys(tabs.value).length;
};

/** 设置标题 */
const setTitle = (tabID: string, title: string): void => {
  if (!tabs.value[tabID]) return;
  tabs.value[tabID].title = title;
};

// 创建新标签页
const createTab = () => {
  emit("addTab");
};
// 激活指定标签页
const activateTab = (tabID: string): void => {
  // 如果新激活的 tabID 等于当前激活的 tabID，直接返回
  if (tabID === currentTabID.value) return;
  // 判断 tabID 是否有效
  if (!tabID || !(tabID in tabs.value)) return;
  // 激活新标签页
  currentTabID.value = tabID;
  // 保存当前标签页
  sessionStorage.setItem("activeTab", tabID);
  // 保存当前标签数组
  sessionStorage.setItem("tabs", JSON.stringify(tabs.value));
  // 触发 changeTab 事件
  emit("changeTab", tabID);
};

// 关闭指定标签页
const closeTab = (tabID: string): void => {
  // 检查ID是否有效
  if (!tabID || !(tabID in tabs.value)) {
    return;
  }

  // 取出页面ID数组
  const tabIDs = Object.keys(tabs.value);
  // 取当前ID的索引
  const index = tabIDs.indexOf(tabID);
  // 删除除标签页ID
  delete tabs.value[tabID];
  // 从 tabIDs 数组中删除
  tabIDs.splice(index, 1);
  // 剩余的标签页数量
  const tabCount = tabIDs.length;
  // 保存标签页对象
  sessionStorage.setItem("tabs", JSON.stringify(tabs.value));
  // 如果没有剩余的页面，则将当前页面ID设置为 null
  if (tabCount === 0) {
    tabs.value = {};
    currentTabID.value = null;
    sessionStorage.setItem("activeTab", "");
    emit("closeTab", tabID, tabCount);
    return;
  } else {
    // 获取新页面ID
    const newTabID =
      index <= tabIDs.length - 1 ? tabIDs[index] : tabIDs[index - 1];
    // 如果关闭的是当前激活标签页，则激活最后一个标签页
    if (tabID === currentTabID.value) {
      currentTabID.value = null;
      activateTab(newTabID);
    }
    emit("closeTab", tabID, tabCount);
    return;
  }
};

// 暴露组件的函数
defineExpose({
  addPage,
  setTitle,
});
</script>

<style lang="less" scoped>
.add-tab-btn.el-button:active {
  background-color: rgba(0, 0, 0, 0.3);
}
.add-tab-btn.el-button:not(:active):hover {
  background-color: rgba(0, 0, 0, 0.2);
}
.add-tab-btn.el-button {
  padding: 0;
  width: 26px;
  height: 26px;
  font-size: 16px;
  font-weight: bold;
  background-color: rgb(224, 224, 224);
  border-radius: 6px;
  margin: auto 0;
  color: black;
  margin-left: 6px;
  cursor: default;
}
.close-btn.el-button:active {
  background-color: rgba(0, 0, 0, 0.3);
}
.close-btn.el-button:not(:active):hover {
  background-color: rgba(0, 0, 0, 0.2);
}
.close-btn {
  display: flex;
  width: 18px;
  height: 18px;
  padding: 0;
  margin: 0;
  margin-left: auto;
  cursor: default;
}

.tab-item.active {
  background-color: #ffffff;
}
.tab-item:not(.active):hover {
  background-color: rgba(0, 0, 0, 0.1);
}
.tab-item {
  display: flex;
  align-items: center;
  padding: 0 12px;
  width: 168px;
  border-radius: 4px 4px 0 0;
  user-select: none;
  background-color: rgb(224, 224, 224);
  overflow: hidden;
  white-space: nowrap;
}
.tab-item-in {
  animation: growWidth 0.15s ease-in-out forwards;
}
.tab-item-out {
  animation: shrinkWidth 0.15s ease-in-out forwards;
}
// 进入动画
@keyframes growWidth {
  from {
    width: 0;
  }
  to {
    width: 168px;
  }
}
// 退出动画
@keyframes shrinkWidth {
  from {
    width: 168px;
  }
  to {
    width: 0;
  }
}

.dynamic-tabs {
  display: flex;
  height: 36px;
  background-color: rgb(224, 224, 224);
}
</style>
